<?php

class sqlite_driver extends cloud_driver {
	
	public function init() {
		
		$connection = sqlite_factory($this->getCredential('file'));
		self::secure('connection', $connection);
		
		$this->hasInit = true;
		return true;
	}
	public function close() {
		
		$connection = self::secure('connection');
		sqlite_close($connection);
		
		return true;
	}
	
	
	public function create_table($name, $columns) {
		
		exit "Not yet implemented";
		
		$cols = array();
		foreach($columns as $key=>$col) {
			if(is_array($col)) {
				
			} elseif(is_string($key)) {
				
			} else {
				
			}
		}
		
		$query = "CREATE TABLE `{$this->prepareSimpleToken($name)}` ()";
		
		return $this->get_table($name);
		
	}
	public function get_table_list() {
		$domain_data = $this->get(array(
			'Action' => 'ListDomains'
		));
		
		$xml = new SimpleXMLElement($domain_data);
		$data = array();
		if($xml->ListDomainsResult) {
			foreach($xml->ListDomainsResult->DomainName as $item)
				$data[] = (string)$item;
			return $data;
		}
	}
	public function get_table($name) {
		$table = new simpledb_table($name);
		
	}
	
	
	public function insert($table, $id, $values) {
		$params = array(
			'Action' => 'PutAttributes',
			'DomainName' => $table,
			'ItemName' => $id
		);
		$vcount = 0;
		foreach($values as $k=>$v) {
			$params["Attribute.$vcount.Name"] = $k;
			$params["Attribute.$vcount.Value"] = $v;
			$params["Attribute.$vcount.Replace"] = true;
			$vcount++;
		}
		$this->get($params);
	}
	
	public function select($table, $where = null, $vars = '*', $order = array(), $limit = -1) {
		
		if(is_array($vars))
			$vars = implode(', ', $this->escapeTokens($vars));
		else
			$vars = $this->escapeToken($vars, '*');
		$expression = "select {$vars} from {$this->escapeString($table)}";
		
		
		// Do ordering early: we need to have all of the included variables in the conditions
		$ordering = null;
		$ordervars = array();
		if(is_array($order) && count($order)) {
			$ordering = array();
			foreach($order as $o) {
				$ordering[] = $this->prepareOrder($o);
				
				$o_var = $o->getVariable();
				if(is_string($o_var))
					$ordervars[] = $o_var;
				elseif(get_class($o_var) == 'simpleToken')
					$ordervars[] = $o_var->getToken();
			}
		}
		
		if(is_array($where)) {
			$conditions = array();
			foreach($where as $wkey=>$c) {
				$cond = $this->escapeToken($wkey);
				$value = $this->escape($c);
				$conditions[] = "$cond = $value";
			}
			
			// All variables that are sorted on must be part of the conditional
			if(isset($ordervars)) {
				foreach($ordervars as $ov) {
					$found = false;
					foreach($where as $k=>$w) {
						if($k == $ov) {
							$found = true;
							break;
						}
					}
					if($found)
						continue;
					$conditions[] = "$ov != ''"; // Make it a simple n
				}
			}
			$expression .= ' where ' . implode(' and ', $conditions);
		}elseif(get_class($where) == 'logicCombinator')
			$expression .= ' where ' . $this->prepareCombinator($where);
		
		
		// Finally output the ordering
		if(isset($ordering))
			$expression .= ' order by ' . implode(', ', $ordering);
		
		// TODO: Consider changing this to Query
		$comm_data = $this->get(array(
			'Action' => 'Select',
			'SelectExpression' => $expression
		));


		$xml = new SimpleXMLElement($comm_data);
		$output = array();
		if($xml->SelectResult) {
			foreach($xml->SelectResult->Item as $item) {
				$item = array();
				foreach($item->Attribute as $attr) {
					$name = (string)$attr->Name;
					$value = (string)$attr->Value;
					$item[$name] = $value;
				}
				$id = (string)$item->Name;
				$output[$id] = $item;
			}
			return $output;
		}
		return false;
	}
	
	public function prepareCombinator($combinator, $nested = false) {
		$logic = $combinator->getLogic();
		$terms = array();
		$raw_terms = $combinator->getTerms();
		foreach($raw_terms as $term) {
			switch(get_class($term)) {
				case 'logicCombinator':
					$terms[] = $this->prepareCombinator($term, true);
					break;
				case 'comparison':
					$terms[] = $this->prepareComparison($term);
					break;
			}
		}
		$output = implode(" $logic ", $terms);
		if($nested)
			$output = "[ $output ]";
		return $output;
	}
	public function prepareComparison($term) {
		$obj1 = $term->getObject1();
		$obj2 = $term->getObject2();
		
		$obj1 = $this->escape($obj1);
		$obj2 = $this->escape($obj2);
		
		return "$obj1 {$term->getOperation()} $obj2";
	}
	public function prepareListOrder($order) {
		$var = $order->getVariable();
		$var = $this->escapeToken($var);
		
		return "$var {$order->getOrder()}";
	}
	
	
	public function escapeString($data) {
		$data = str_replace("'", "''", $data);
		return $data;
	}
	
	public function escapeInteger($data) {
		$data = intval($data);
		$data = str_pad($data, SIMPLEDB_INT_LENGTH, '0', STR_PAD_LEFT);
		return $data;
	}
	
	public function escapeFloat($data) {
		$rounded = round($data);
		$length = strlen((string)$rounded);
		$length = $length + 6 - ($length % 6);
		$output = str_pad($round, $length, '0', STR_PAD_LEFT);
		if($data != $rounded) {
			$output .= '.';
			$decimal = substr((string)($data - $rounded), 2);
			$decimallength = strlen($decimal);
			$decimallength = $decimallength + 3 - ($decimallength % 3);
			$output .= str_pad($decimal, $decimallength, '0', STR_PAD_RIGHT);
		}
		return $output;
	}
	
	public function prepareSimpleTokens($tokens) {
		$output = array();
		foreach($tokens as $token)
			if(ctype_alnum($token))
				$output[] = $token;
		return $output;
	}
	public function prepareSimpleToken($token, $default = '') {
		if(ctype_alnum($token))
			return $token;
		else
			return $default;
	}
	
	private function getCredential($key) {
		$creds = self::secure('credentials');
		$data = $creds->$key;
		return $data;
	}
	public function get($parameters) {
		
		// Build out the variables
		$host = 'sdb.amazonaws.com';
		$domain = "https://$host/";
		$parameters['AWSAccessKeyId'] = $this->getCredential('api_key');
		$parameters['Timestamp'] = date('c');
		$parameters['Version'] = '2007-11-07';
		$parameters['SignatureMethod'] = 'HmacSHA256';
		$parameters['SignatureVersion'] = 2;
		
		
		// Write the signature
		$signature = "GET\n";
		$signature .= "$host\n";
		$signature .= "/\n";
		
		$sigparams = $parameters;
		
		ksort($sigparams);
		
		$first = true;
		foreach($sigparams as $key=>$param) {
			$signature .= (!$first ? '&' : '') . rawurlencode($key) . '=' . rawurlencode($param);
			if($first)
				$first = false;
		}
		
		//echo $signature;
		
		$signature = hash_hmac('sha256', $signature, $this->getCredential('api_secret'), true);
		$signature = base64_encode($signature);
		
		// Build out the query url
		$parameters['Signature'] = $signature;
		
		$url = $domain . '?';
		$first = true;
		foreach($parameters as $key=>$param) {
			$url .= (!$first ? '&' : '') . rawurlencode($key) . '=' . rawurlencode($param);
			$first = false;
		}
		
		//echo $url;
		
		// Make the final request
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		
		$output = curl_exec($ch);
		
		return $output;
		
	}
	
	public function supports_function($name) {
		$supported_functions = array(
			'LIKE',
			'NOT LIKE',
			'IS NULL',
			'IS NOT NULL',
			'STARTS WITH'
		);
		return in_array($name, $supported_functions);
	}
	
}

class sqlite_table implements cloud_driver_table {
	
	public function __construct($driver, $table) {
		self::secure('driver', $driver);
		self::secure('table', $table);
	}
	
	public function destroy() {
		$driver = self::secure('driver');
		$driver->get(array(
			'Action' => 'DeleteDomain',
			'DomainName' => self::secure('table')
		));
		
		// Delete any sensitive information from memory
		self::secure('driver', false, true);
		self::secure('table', false, true);
		
	}
	
	public function get_driver() {return self::secure('driver');}
	
	public function get_columns() {
		
	}
	
}
